﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Compiler
{
    /// <summary>
    /// 语法分析
    /// </summary>
    public static class SyntaxAnalysis
    {
        /// <summary>
        /// 分析栈
        /// </summary>
        public static Stack<string> mStack = new Stack<string>();
        public static void Analyse()
        {
            if (Parser.Parse())
            {
                Compiler.WriteLine("分析完成");
            }
            else
            {
                Compiler.WriteLine("分析失败");
            }
        }

        public static void Init()
        {
            mStack.Clear();
            mStack.Push("#");
            mStack.Push("Program");
            Parser.mTokens = Token.Queue;
            Parser.mTerminator = PredictiveAnalyzeTable.Terminator;
            Parser.mTable = PredictiveAnalyzeTable.Table;
            Parser.productions = Production.Productions;
            Parser.transProductions = Production.TransProductions;
        }
        /// <summary>
        /// 语法分析器
        /// </summary>
        private static class Parser
        {
            public static Queue<Token> mTokens;
            public static Dictionary<string, int> mTerminator;
            public static Dictionary<string, List<int>> mTable;
            public static List<KeyValuePair<string, string>> productions;
            public static List<KeyValuePair<string, string>> transProductions;

            public static bool Parse()
            {
                Token value = null;
                while (mTokens.Count > 0)
                {
                    Token token = mTokens.Peek();
                    int index = mTerminator[token.Lexeme];
                    string top = mStack.Peek();
                    //以@的是语义操作
                    if (top.StartsWith("@"))
                    {
                        IntermediateCodeGeneration.Generate(mStack.Pop(), value);
                        continue;
                    }

                    Compiler.WriteLine();
                    //分析完成
                    if (top == "#") break;
                    //匹配
                    if (top == token.Lexeme)
                    {
                        mStack.Pop();
                        value = mTokens.Dequeue();
                        //输出当前操作
                        Compiler.WriteLine($" {CurrentStateToString()} 匹配 {top}");
                        continue;
                    }

                    int idx = -1;
                    //获取产生式的index
                    try
                    {
                        idx = mTable[top][index];

                    }
                    catch (Exception e)
                    {
                        Compiler.Log(e);
                        Compiler.Log(new Exception($" !!! {top} {token.Lexeme} {idx}"));
                    }
                    //没有合适的产生式
                    if (idx == -1)
                    {
                        Compiler.Log(new Exception("规约失败"));
                        return false;
                    }
                    //输出
                    else
                    {
                        //获取产生式
                        //var production = productions[idx];
                        var production = transProductions[idx];
                        //left出栈
                        mStack.Pop();
                        //rights入栈
                        List<string> rights = new List<string>(production.Value.Split(new char[] { ' ' }));
                        rights.Reverse();
                        foreach (string s in rights)
                        {
                            if (s == "$") continue;
                            mStack.Push(s);
                        }
                        //输出当前操作
                        Compiler.WriteLine($" {CurrentStateToString()} 输出{production}");
                    }
                }
                return true;
            }
            /// <summary>
            /// 将当前堆栈状态转换成字符串
            /// </summary>
            private static string CurrentStateToString() => $"{string.Join(" ", mStack.Reverse().Where(o => !o.StartsWith("@"))),-50}\t{string.Join(" ", mTokens.Select(o => o.Lexeme)),-50}\t";
        }
    }

}
